package com.fxu.gen;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.fxu.framework.core.base.Constant;
import com.fxu.framework.core.util.DiffUtil;
import com.fxu.gen.enums.ClnType;
import com.fxu.gen.enums.IndexType;
import com.fxu.gen.enums.TplEnum;
import com.fxu.tpl.entity.Column;
import com.fxu.tpl.entity.Index;
import com.fxu.tpl.entity.Table;

import java.io.File;
import java.util.List;

/**
 * MySQL语句，根据表结构历史情况，创建SQL的执行代码
 */
public final class MySQL extends Base {
	public MySQL(Table table, File destFile) {
		super(table, TplEnum.SQL, destFile);
	}

	@Override
	public String doReplace() {
		return getCreate().toString();
	}

	private StringBuffer getCreate() {
		StringBuffer buffer = new StringBuffer();
		buffer.append(StrUtil.format("CREATE TABLE `{}`(\n", table.getName()));
		for (Column column : columns) {
			buffer.append(getColumnSql("", column));
		}
		for (Index index : indexs) {
			buffer.append(StrUtil.format("  {} `{}` ({}),\n", getIndType(index), index.getName(), getIdxClnList(index)));
		}
		AutoUtil.moveLastDot(buffer);
		buffer.append("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
		buffer.append(" COMMENT='").append(table.getCmmt()).append("';");
		return buffer;
	}

	/**
	 * 修改表结构
	 * @param oldTable 旧表
	 * @return Alter 语句
	 */
	public StringBuffer getAlter(Table oldTable) {
		StringBuffer buffer = new StringBuffer();

		DiffUtil.Diff<Column> diffCln = DiffUtil.getDiff(oldTable.getColumnList(), table.getColumnList(), true);
		for (Column column : diffCln.deletes) {
			buffer.append(StrUtil.format("  {} `{}`,\n", "DROP", column.getName()));
		}
		for (Column column : diffCln.inserts) {
			buffer.append(getColumnSql("ADD", column, getPrevColumnName(table.getColumnList(), column)));
		}
		for (Column column : diffCln.updates) {
			Column oldCln = CollUtil.findOne(oldTable.getColumnList(), v -> v.getId().equals(column.getId()));
			if (oldCln.getName().equals(column.getName())) {
				buffer.append(getColumnSql("MODIFY", column));
			} else {
				buffer.append(getColumnSql("CHANGE " + oldCln.getName(), column));
			}
		}
		if (buffer.length() > 0) {
			buffer.insert(0, StrUtil.format("ALTER TABLE `{}`\n", table.getName()));
			AutoUtil.moveLastDot(buffer).append(";\n");
		}

		DiffUtil.Diff<Index> diffIdx = DiffUtil.getDiff(oldTable.getIndexList(), table.getIndexList(), true);
		if (!CollUtil.isEmpty(diffIdx.deletes)) {
			diffIdx.deletes.addAll(diffIdx.updates);
			buffer.append(StrUtil.format("ALTER TABLE `{}`\n", table.getName()));
			for (Index index : diffIdx.deletes) {
				buffer.append(StrUtil.format("  DROP KEY `{}`,\n", index.getName()));
			}
			AutoUtil.moveLastDot(buffer).append(";\n");
		}
		if (!CollUtil.isEmpty(diffIdx.inserts) || !CollUtil.isEmpty(diffIdx.updates)) {
			diffIdx.inserts.addAll(diffIdx.updates);
			buffer.append(StrUtil.format("ALTER TABLE `{}`\n", table.getName()));
			for (Index index : diffIdx.inserts) {
				buffer.append(StrUtil.format("  ADD {} `{}` ({}),\n", getIndType(index),
						index.getName(), getIdxClnList(index)));
			}
			AutoUtil.moveLastDot(buffer).append(";\n");
		}
		return buffer;
	}

	private String getPrevColumnName(List<Column> columns, Column column) {
		for (int i = 0, size = columns.size(); i < size; i++) {
			if (columns.get(i).getName().equals(column.getName())) {
				return columns.get(i-1).getName();
			}
		}
		return "";
	}

	private String getColumnSql(String action, Column cln) {
		return getColumnSql(action, cln, "");
	}

	private String getColumnSql(String action, Column cln, String prevCln) {
		return StrUtil.format("  {}`{}` {}{}{}{}{} COMMENT '{}'{},\n", action == null ? "" : action +  " ",
				cln.getName(), AutoUtil.getSqlType(cln), getLength(cln), getUnsigned(cln), getNotNull(cln), getDefVal(cln),
				cln.getCmmt() + (Entity.hasLimits(cln.getLimits()) ? "(" + cln.getLimits() + ")" : ""),
				StrUtil.isEmpty(prevCln) ? "" : " AFTER " + prevCln);
	}

	private String getUnsigned(Column cln) {
		return cln != null && isTrue(cln.getUnsigned()) ? " unsigned" : "";
	}

	private String getNotNull(Column cln) {
		return cln != null && isTrue(cln.getNotNull()) ? " NOT NULL" : "";
	}

	private String getDefVal(Column column) {
		if (priKeyCln.equals(column.getName()) && (column.getType().equals(ClnType.INTEGER.code())
				|| column.getType().equals(ClnType.LONG.code()))) {
			return " AUTO_INCREMENT";
		}
		String defVal = column.getDefVal();
		if (Constant.CLN_MODIFY_TIME.equals(column.getName())) {
			defVal = "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP";
		} else if ("空".equals(defVal)) {
			defVal = "''";
		} else if ("NOW".equals(defVal)) {
			defVal = "CURRENT_TIMESTAMP";
		} else {
			defVal = "'"+defVal+"'";
		}
		return StrUtil.isEmpty(column.getDefVal()) ? "" : " DEFAULT " + defVal;
	}

	private String getIdxClnList(Index index) {
		String value = index.getColumns().replace(",", "`, `");
		if (value.length() == 0) {
			value = priKeyCln;
		}
		return "`" + value + "`";
	}

	private String getIndType(Index idx) {
		if (idx.getColumns() != null && priKeyCln.equals(idx.getColumns()) && idx.getName().equals("idx_prikey")) {
			return IndexType.PRIMARY_KEY.desc();
		}
		if (IndexType.find(idx.getType()) == IndexType.UNIQUE_KEY) {
			return IndexType.UNIQUE_KEY.desc();
		}
		return IndexType.KEY.desc();
		//return IndexType.find(idx.getType()).desc();
	}

	private String getLength(Column cln) {
		String length = cln.getLength() + "";
		if (cln.getType().equals(ClnType.DECIMAL.code()) && cln.getDotRight() != null) {
			length = cln.getLength() + "," + cln.getDotRight();
		}
		return cln.getLength() == 0 ? "" : "("+length+")";
	}

	private void sysOut(List<Column> columnList, int i) {
		System.out.println("=============="+i+"=============");
		for (Column column : columnList) {
			System.out.println(StrUtil.format("{}, {}", column.getId(), column.getName()));
		}
	}
}
